﻿/**
**		File : pak_kernel.cpp
**		Author : beyondcode
**		Date : 2010/05/31
**		Des : beyondpak 核心函数实现
**
**/

#include "pak_kernel.h"
#include "pak_io.h"
#include <stdio.h>
#include <debugheader.h>

static void _GetPlatformInfo();
static const char* _MapPlatformName( int nPlatId );
static int _SaveOnePakNode( FILE* pFile, PPAK_DIR_NODE pDirNode, PPAK_STACK pStack, long* piRecordOffset, long* piContentOffset, PPAK_PKG pPkg, SAVE_NODE_VALUE pfnSaveValue );
static int _SaveValue( FILE* pFile, PPAK_DIR_NODE pDirNode, long iValueOffset, size_t* punValueLen, PPAK_PKG pPkg, void* psExtra );
static void* _LoadValue( FILE* pFile, PPAK_DIR_NODE_RECORD pDirNodeRecord, void* psExtra );
static int _SaveHeader( FILE* pFile, size_t nRecordCount, long* piRecordOffset, long* piContentOffset );
static int _ExtractOneFile( FILE* pPkgFile, FILE* pExtractFile, PPAK_DIR_NODE_RECORD pRecord, PPAK_PKG pPkg, PPAK_DIR_NODE pCurDir, const char* pszFullName );

static int _LoadHeader( FILE* pFile, PPAK_PKG_HEAD pPkgHeader );
static int _LoadRecords( FILE* pFile, PPAK_DIR_NODE_RECORD pPkgRecords, size_t nRecordCount );
static PPAK_DIR_NODE _GeneratePakNodeByRecords( PPAK_DIR_NODE_RECORD pPkgRecords, size_t nPkgRecord, FILE* pFile, LOAD_NODE_VALUE pfnLoadValue, PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnDestory );
static PPAK_DIR_NODE_RECORD _FindRecord( PPAK_DIR_NODE_RECORD pPkgRecords, size_t nRecordCount, size_t nID );

static int _SavePakNode( PPAK_PKG pPkg, PPAK_DIR_NODE pDirNodeRoot, const char* pszSaveFileName, SAVE_NODE_VALUE pfnSaveValue );
const char* g_cpszPlatName[] = 
{
	"win32",
	"linux",
	"unix"
};

void GetPlatformInfo( )
{
	_GetPlatformInfo();
}

PPAK_DIR_STATUS OpenDir( const char* pszDir )
{
	return _OpenDir( pszDir );
}
const PPAK_DIR ReadDir( PPAK_DIR_STATUS pDirStatus )
{
	return _ReadDir( pDirStatus );
}
int CloseDir( PPAK_DIR_STATUS pDirStatus )
{
	return _CloseDir( pDirStatus );
}

PPAK_PKG LoadDirTreePackage( const char* pszu8PathName )
{
	int bResutl = 0;
	PPAK_PKG psPkg = NULL;

	PROCESS_ERROR( pszu8PathName );
	PROCESS_ERROR( psPkg = LoadPackage( pszu8PathName, &_LoadValue, _CreatePakDir, _DestroyPakDir ) );
	bResutl = 1;

Exit0:
	if ( 0 == bResutl )
	{
		if ( psPkg )
		{
			DeletePackage( psPkg );
			psPkg = NULL;
		}
	}
	return psPkg;
}
PPAK_PKG CreateDirTreePackage( const char* pszu8PathName )
{
	int bResutl = 0;
	PPAK_PKG psPkg = NULL;
	PPAK_DIR_NODE psNodeRoot = NULL;

	PROCESS_ERROR( pszu8PathName );
	PROCESS_ERROR( psPkg = CreatePackage() );
	PROCESS_ERROR( psNodeRoot = GenerateDirTreeByPath( pszu8PathName ) );
	PROCESS_ERROR( SetPackageValue( psPkg, psNodeRoot ) );
	psNodeRoot = NULL;
	bResutl = 1;

Exit0:
	if ( 0 == bResutl )
	{
		if ( psPkg )
		{
			DeletePackage( psPkg );
			psPkg = NULL;
		}
		if ( psNodeRoot )
		{
			DestroyPakNodeEx( psNodeRoot );
			psNodeRoot = NULL;
		}
	}
	return psPkg;
}
int SaveDirTreePackage( PPAK_PKG pPkg, const char* pszu8Pathname )
{
	int bResult = 0;

	PROCESS_ERROR( pPkg && pszu8Pathname );
	PROCESS_ERROR( SavePackage( pPkg, pszu8Pathname, &_SaveValue ) );
	bResult = 1;

Exit0:
	return bResult;
}
PPAK_DIR_NODE GenerateDirTreeByPath( const char* pszRootDir )
{
	int					bResult  = 0;
	PPAK_DIR_STATUS		pDirStatus = 0;
	PPAK_STACK			pDirStack = 0;
	PPAK_STACK_ITEM		pDirNewItem = 0;
	PPAK_STACK_ITEM		pDirCurItem = 0;
	PPAK_DIR_NODE		pRootDirNode = 0;
	size_t				nCurID = 1;
	char*				pszFullPath = NULL;
	size_t				nFullPathLen = 0;
	size_t				nFullPathMaxLen = PAK_FULLPATH_MAXLEN;
	
	//Create initial directory struct and set directory name
	PROCESS_ERROR( pRootDirNode = _GetDirNode( _CreatePakDir, _DestroyPakDir ) );
	PROCESS_ERROR( _SetDirNodeName( pRootDirNode, pszRootDir ) );
	PROCESS_ERROR( _SetDirNodeID( pRootDirNode, nCurID ) );
	nCurID++;

	//Create directory struct stack and creat and push initial directory struct
	PROCESS_ERROR( pDirStack = _NewStack() );
	PROCESS_ERROR( pDirNewItem = _NewStackItem() );
	pDirNewItem->pValue = pRootDirNode;
	PROCESS_ERROR( _PushStack( pDirStack, pDirNewItem ) );
	pDirNewItem = NULL;
	
	//Init FullPath buffer
	PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathMaxLen ) );

	while( pDirCurItem = _PopStack( pDirStack ) )
	{
		PPAK_DIR pDir = 0;
		PPAK_DIR pCurDir = NULL;
		PPAK_DIR_NODE pDirNewNode = 0;
		PPAK_DIR_NODE pDirCurNode = 0;

		pDirCurNode = (PPAK_DIR_NODE)pDirCurItem->pValue;
		_DelStackItem( pDirCurItem );
		pDirCurItem = 0;

		pCurDir = ( PPAK_DIR )pDirCurNode->psValue;
		if( pCurDir->nType == DIRTYPE_FILE )
		{
			//Is file
			continue;
		}

		//Get full directory name and open the directory
		nFullPathLen = nFullPathMaxLen;
		if( !_GetDirNodeFullPath( pDirCurNode, pszFullPath, &nFullPathLen) )
		{
			PROCESS_ERROR( nFullPathLen > nFullPathMaxLen );
			if( pszFullPath )
				free( pszFullPath );
			PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathLen ) );
			nFullPathMaxLen = nFullPathLen;
			PROCESS_ERROR( _GetDirNodeFullPath( pDirCurNode, pszFullPath, &nFullPathLen ) );
		}

		pDirStatus = _OpenDir( pszFullPath );
		if( !pDirStatus )
			continue;

		while( pDir = _ReadDir( pDirStatus ) )
		{
			int	bLoopResult = 0;
			
			//Filter Directory
			PROCESS_LOOP_ERROR( _FilterDir( pDir, DefaultDirFilter ) );

			PROCESS_LOOP_ERROR( pDirNewNode = _GetDirNode( _CreatePakDir, _DestroyPakDir ) );
			PROCESS_LOOP_ERROR( _SetDirNodeName( pDirNewNode, pDir->pszName ) );
			PROCESS_LOOP_ERROR( _SetDirNodeType( pDirNewNode, pDir->nType ) );
			PROCESS_LOOP_ERROR( _SetDirNodeParent( pDirNewNode, pDirCurNode ) );
			PROCESS_LOOP_ERROR( _SetDirNodeID( pDirNewNode, nCurID ) );
			nCurID++;

			PROCESS_LOOP_ERROR( pDirNewItem = _NewStackItem() );
			pDirNewItem->pValue = pDirNewNode;

			PROCESS_LOOP_ERROR( _PushStack( pDirStack, pDirNewItem ) );

			pDirNewNode = NULL;
			pDirNewItem = NULL;
			bLoopResult = 1;
			LoopExit0:
			if( 0==bLoopResult )
			{
				if( pDirNewNode )
				{
					_RecycleDirNode( pDirNewNode );
					pDirNewNode = NULL;
				}
				if( pDirNewItem ) 
				{
					_DelStackItem( pDirNewItem );
					pDirNewItem = NULL;
				}
			}
		}
		_CloseDir( pDirStatus );
		pDirStatus = 0;
	};

	pDirNewItem = NULL;
	pDirCurItem = NULL;
	bResult = 1;
Exit0:
	if( 0==bResult )
	{
		//Release DirStatus
		_CloseDir( pDirStatus );
		//Release stack item's memory

		//Release DirNode tree's memory
		_RecycleDirNode( pRootDirNode );
		pRootDirNode = 0;
	}
	
	if( pszFullPath )
		free( pszFullPath );
	if( pDirNewItem )
	{
		_RemoveStackItem( pDirStack, pDirNewItem );
		_DelStackItem( pDirNewItem );
	}
	if( pDirStack )
		_DelStack( pDirStack );
	
	return pRootDirNode;
}


PPAK_DIR_NODE _GeneratePakNodeByRecords( PPAK_DIR_NODE_RECORD pPkgRecords, size_t nPkgRecord, FILE* pFile, LOAD_NODE_VALUE pfnLoadValue, PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnValueDestory)
{
	int					bResult = 0;
	PPAK_DIR_NODE		pDirRoot = NULL, pNewNode = NULL, pCurNode = NULL;
	PPAK_STACK			pStack = NULL;
	PPAK_STACK_ITEM		pNewStackItem = NULL, pCurStackItem = NULL;
	size_t*				punChildrenID = NULL;
	void*				psValue = NULL;

	PROCESS_ERROR( pPkgRecords && pFile );
	PROCESS_ERROR( pStack = _NewStack() );
	PROCESS_ERROR( pNewStackItem = _NewStackItem() );
	pNewStackItem->pValue = pPkgRecords;
	pNewStackItem->pValueExtra1 = NULL;
	PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
	pNewStackItem = NULL;

	while( pCurStackItem = _PopStack( pStack ) )
	{
		PPAK_DIR_NODE_RECORD	pCurRecord = NULL;
		PPAK_DIR_NODE	pParentNode = NULL;
		size_t			nChildrenIDCount = 0;
		size_t			nRecordNameLen = 0;
		size_t			nRead = 0, nRealRead = 0;
		size_t			i = 0;

		pCurRecord = (PPAK_DIR_NODE_RECORD)pCurStackItem->pValue;
		pParentNode = (PPAK_DIR_NODE)pCurStackItem->pValueExtra1;
		PROCESS_ERROR( _DelStackItem( pCurStackItem ) );
		pCurStackItem = NULL;
		
		nRead = pCurRecord->nChildrenLen;
		PROCESS_ERROR( punChildrenID = (size_t*)malloc( nRead ) );
		PROCESS_ERROR( _ReadFileAt( pFile, (char*)punChildrenID, nRead, &nRealRead, pCurRecord->nChildren) );
		PROCESS_ERROR( nRead == nRealRead );
		nChildrenIDCount = pCurRecord->nChildrenLen / sizeof(size_t);

		//PROCESS_ERROR( psValue = _LoadValue( pFile, pCurRecord, NULL ) );
		PROCESS_ERROR( pfnLoadValue );
		PROCESS_ERROR( psValue = pfnLoadValue( pFile, pCurRecord, NULL ) );

		PROCESS_ERROR( pNewNode = _GetDirNode( pfnValueCreator, pfnValueDestory) );
		PROCESS_ERROR( _SetDirNodeID( pNewNode, pCurRecord->nID ) );
		PROCESS_ERROR( _SetDirNodeValue( pNewNode, psValue ) );
		psValue = NULL;	//重置为NULL,防止本函数出错时被重复释放
		
		if( pParentNode )
		{
			PROCESS_ERROR( _SetDirNodeParent( pNewNode, pParentNode ) );
		}
		else
		{
			if( !pDirRoot )
			{ pDirRoot = pNewNode; }
			else
			{ }
		}
		pCurNode = pNewNode;
		pNewNode = NULL;

		for ( i = 0; i < nChildrenIDCount; i++ )
		{
			PPAK_DIR_NODE_RECORD pChildRecord = NULL;
			PROCESS_ERROR( pChildRecord = _FindRecord( pPkgRecords, nPkgRecord, punChildrenID[i] ) );
			PROCESS_ERROR( pNewStackItem = _NewStackItem() );
			pNewStackItem->pValue = pChildRecord;
			pNewStackItem->pValueExtra1 = pCurNode;
			PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
			pNewStackItem = NULL;
		}
		
		free( punChildrenID );
		punChildrenID = NULL;
	}

	bResult = 1;
Exit0:
	if( 0==bResult )
	{
		if( pDirRoot )
			DestroyPakNodeEx( pDirRoot );
		pDirRoot = NULL;
	}

	if( punChildrenID )
		free( punChildrenID );
	if ( psValue )
	{
		_DestroyPakDir( psValue );
	}
	if( pNewNode )
	{
		_RecycleDirNode( pNewNode );
	}
	if( pNewStackItem )
	{
		_RemoveStackItem( pStack, pNewStackItem );
		_DelStackItem( pNewStackItem );
	}
	if( pStack )
	{
		_DelStack( pStack );
	}
	return pDirRoot;
}

int _SavePakNode( PPAK_PKG pPkg, PPAK_DIR_NODE pDirNodeRoot, const char* pszSaveFileName, SAVE_NODE_VALUE pfnSaveValue )
{
	int				bResult = 0;
	PPAK_STACK		pStack = NULL;
	PPAK_STACK_ITEM	pNewStackItem = NULL, pCurStackItem = NULL;

	FILE*			pFile = NULL;
	long			iRecordOffset = 0,
					iContentOffset = 0;
	size_t			nNodeCount = 0, nSaveNodeCount = 0;
	
	PROCESS_ERROR( pDirNodeRoot && pszSaveFileName );
	PROCESS_ERROR( pFile = _OpenFile( pszSaveFileName, "wb" ) );

	PROCESS_ERROR( nNodeCount = EnumPakNodeCount( pDirNodeRoot, NULL, NULL ) );
	iRecordOffset = 0;
	iContentOffset = (long)(nNodeCount * sizeof( PAK_DIR_NODE_RECORD ) + sizeof(PAK_PKG_HEAD) );

	PROCESS_ERROR( _SaveHeader( pFile, nNodeCount, &iRecordOffset, &iContentOffset ) );

	PROCESS_ERROR( pStack = _NewStack() );
	PROCESS_ERROR( pNewStackItem = _NewStackItem() );
	pNewStackItem->pValue = pDirNodeRoot;
	PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
	pNewStackItem = NULL;

	while( pCurStackItem = _PopStack( pStack ) )
	{
		PPAK_DIR pCurPakDir = NULL;
		PPAK_DIR_NODE pCurNode = NULL;
		pCurNode = (PPAK_DIR_NODE)pCurStackItem->pValue;
		PROCESS_ERROR( _DelStackItem( pCurStackItem ) );
		pCurStackItem = NULL;

		PROCESS_ERROR( pCurNode );
		PROCESS_ERROR( pCurPakDir = ( PPAK_DIR )pCurNode->psValue );
		
		if( pPkg->apfnCallbacks[ON_PRE_PACKFILE] )
			pPkg->apfnCallbacks[ON_PRE_PACKFILE]( pCurNode, nSaveNodeCount, nNodeCount, NULL );
		PROCESS_ERROR( _SaveOnePakNode( pFile, pCurNode, pStack, &iRecordOffset, &iContentOffset, pPkg, pfnSaveValue ) );
		nSaveNodeCount++;
		if( pPkg->apfnCallbacks[ON_POST_PACKFILE] )
			pPkg->apfnCallbacks[ON_POST_PACKFILE]( pCurNode, nSaveNodeCount, nNodeCount, NULL );
	}

	bResult = 1;
Exit0:
	if( pNewStackItem )
	{
		_RemoveStackItem( pStack, pNewStackItem );
		_DelStackItem( pNewStackItem );
	}
	if( pStack )
	{
		_DelStack( pStack );
	}
	if( pFile )
		_CloseFile( pFile );
	return bResult;
}

int EnumPakNodeCount( PPAK_DIR_NODE pDirNodeRoot, EnumPakNodeCallback pfnCallback, void* pCallbackParam )
{
	int				bResult = 0;
	int				nCount = 0;
	PPAK_STACK		pStack = NULL;
	PPAK_STACK_ITEM	pNewItem = NULL, pCurItem = NULL;

	//Push root node
	PROCESS_ERROR( pDirNodeRoot );
	PROCESS_ERROR( pStack = _NewStack() );
	PROCESS_ERROR( pNewItem = _NewStackItem() );
	pNewItem->pValue = pDirNodeRoot;
	PROCESS_ERROR( _PushStack( pStack, pNewItem ) );
	pNewItem = NULL;
	nCount++;

	while( pCurItem = _PopStack( pStack ) )
	{
		PPAK_DIR_NODE	pCurNode = NULL;

		pCurNode = (PPAK_DIR_NODE)pCurItem->pValue;
		_DelStackItem( pCurItem );
		pCurItem = NULL;

		if ( pfnCallback )
		{
			pfnCallback( pCurNode, pCallbackParam );
		}

		pCurNode = pCurNode->pChildPakDir;
		while( pCurNode )
		{
			PROCESS_ERROR( pNewItem = _NewStackItem() );
			pNewItem->pValue = pCurNode;
			PROCESS_ERROR( _PushStack( pStack, pNewItem ) );
			pNewItem = NULL;
			nCount++;
			pCurNode = pCurNode->pBrotherPakDir;
		}
	}

	bResult = nCount;
Exit0:
	if( 0==bResult )
	{
		if( pCurItem )
		{
			_RemoveStackItem( pStack, pCurItem );
			_DelStackItem( pCurItem );
			pCurItem = NULL;
		}
		if( pNewItem )
		{
			_RemoveStackItem( pStack, pNewItem );
			_DelStackItem( pNewItem );
			pNewItem = NULL;
		}
	}

	if( pStack )
		_DelStack( pStack );

	return bResult;
}

int AToU2( const char* lpszSrcA, size_t nSrcALen, wchar_t* lpwszDestU2, size_t nDestU2Len )
{
	return _AToU2( lpszSrcA, nSrcALen, lpwszDestU2, nDestU2Len );
}
int U2ToA( const wchar_t* lpwszSrcU2, size_t nSrcU2Len, char* lpszDestA, size_t nDestALen )
{
	return _U2ToA( lpwszSrcU2, nSrcU2Len, lpszDestA, nDestALen );
}

int U2ToU8( const wchar_t* lpwszSrcU2, size_t nSrcU2Len, char* lpszDestU8, size_t nDestU8Len )
{
	return _U2ToU8( lpwszSrcU2, nSrcU2Len, lpszDestU8, nDestU8Len );
}

int U8ToU2( const char* lpszSrcU8, size_t nSrcU8Len, wchar_t* lpwszDestU2, size_t nDestU2Len )
{
	return _U8ToU2( lpszSrcU8, nSrcU8Len, lpwszDestU2, nDestU2Len );
}

int AToU8( const char* lpszSrcA, size_t nSrcALen, char* lpszDestU8, size_t nDestU8Len )
{
	return _AToU8( lpszSrcA, nSrcALen, lpszDestU8, nDestU8Len );
}

int U8ToA( const char* lpszSrcU8, size_t nSrcU8Len, char* lpszDestA, size_t nDestALen )
{
	return _U8ToA( lpszSrcU8, nSrcU8Len, lpszDestA, nDestALen );
}


static void _GetPlatformInfo()
{
	printf( "Platform:%s\n", _MapPlatformName(PAK_PLAT) );
	printf( "beyondcode Copyright All Reserverd\n" );
}

static const char* _MapPlatformName( int nPlatId )
{
	return g_cpszPlatName[ nPlatId-1 ];
}

int _SaveOnePakNode( FILE* pFile, PPAK_DIR_NODE pDirNode, PPAK_STACK pStack, long* piRecordOffset, long* piContentOffset, PPAK_PKG pPkg, SAVE_NODE_VALUE pfnSaveValue )
{
	int				bResult = 0;
	PPAK_STACK_ITEM pNewStackItem = NULL;
	PPAK_DIR_NODE	pChildNode = NULL;
	PPAK_DIR		pDir = NULL;
	PAK_DIR_NODE_RECORD	pdr = { 0 };


	long			iNewRecordOffset = 0, iNewContentOffset = 0;
	size_t*			pnChildrenNodeID = NULL;
	size_t			nChildrenNodeIDTotal = 0, nChildrenNodeIDLeft = 0, nChildrenNodeCount = 0;
	size_t			nWrite = 0, nRealWrite = 0;
	size_t			unValueLen = 0;

	PROCESS_ERROR( pFile && pDirNode && pStack && piRecordOffset && piContentOffset );
	PROCESS_ERROR( pDir = (PPAK_DIR)pDirNode->psValue );
	iNewRecordOffset = *piRecordOffset;
	iNewContentOffset = *piContentOffset;
	//记录该节点的基本信息
	pdr.nID = pDirNode->nNodeID;

	if( pDirNode->pChildPakDir )
	{
		//初始化子节点ID缓冲区
		PROCESS_ERROR( pnChildrenNodeID = (size_t*)malloc( sizeof(size_t) * PAK_CHILDREN_ID_COUNT ) );
		nChildrenNodeIDTotal = nChildrenNodeIDLeft = PAK_CHILDREN_ID_COUNT;
		nChildrenNodeCount = 0;

		//获取该节点的所有子节点的ID，并存储到ID缓冲区中
		pChildNode = pDirNode->pChildPakDir;
		while( pChildNode )
		{
			PROCESS_ERROR( pNewStackItem = _NewStackItem() );
			pNewStackItem->pValue = pChildNode;
			PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
			pNewStackItem = NULL;

			//检查子节点ID缓冲区容量
			if ( nChildrenNodeIDLeft <= 0 )
			{
				size_t* pnNewChildrenNodeId = NULL;
				PROCESS_ERROR( pnNewChildrenNodeId = realloc( pnChildrenNodeID, sizeof(size_t) * ( nChildrenNodeIDTotal + PAK_CHILDREN_ID_COUNT ) ) );
				pnChildrenNodeID = pnNewChildrenNodeId;
				nChildrenNodeIDTotal += PAK_CHILDREN_ID_COUNT;
				nChildrenNodeIDLeft = PAK_CHILDREN_ID_COUNT;
			}
			pnChildrenNodeID[nChildrenNodeCount++] = pChildNode->nNodeID;
			nChildrenNodeIDLeft--;

			pChildNode = pChildNode->pBrotherPakDir;
		}
		//记录该节点的子节点ID信息的偏移以及长度并写入文件
		nWrite = sizeof(size_t) * nChildrenNodeCount;
		pdr.nChildren = iNewContentOffset;
		pdr.nChildrenLen = nWrite;

		PROCESS_ERROR( _WriteFileAt( pFile, (char*)pnChildrenNodeID, nWrite, &nRealWrite, iNewContentOffset ) );
		PROCESS_ERROR( nRealWrite == nWrite );
		iNewContentOffset += (long)nWrite;
	}
	else
	{
		pdr.nChildren = 0;
		pdr.nChildrenLen = 0;
	}

	//用户数据
	//PROCESS_ERROR( _SaveValue( pFile, pDirNode,iNewContentOffset, &unValueLen, pPkg, NULL ) );
	PROCESS_ERROR( pfnSaveValue );
	PROCESS_ERROR( pfnSaveValue( pFile, pDirNode, iNewContentOffset, &unValueLen, pPkg, NULL ) );
	pdr.nValueRecord = iNewContentOffset;
	pdr.nValueRecordLen = unValueLen;
	iNewContentOffset += (long)unValueLen;
	


	//写入该节点的记录信息
	nWrite = sizeof(PAK_DIR_NODE_RECORD);
	PROCESS_ERROR( _WriteFileAt( pFile, (char*)&pdr, nWrite, &nRealWrite, iNewRecordOffset ) );
	PROCESS_ERROR( nWrite == nRealWrite );
	iNewRecordOffset += (long)nWrite;

	*piContentOffset = iNewContentOffset;
	*piRecordOffset = iNewRecordOffset;
	bResult = 1;
Exit0:

	if( pnChildrenNodeID )
		free( pnChildrenNodeID );
	if( pNewStackItem )
	{
		_RemoveStackItem( pStack, pNewStackItem );
		_DelStackItem( pNewStackItem );
	}
	return bResult;
}

int _SaveHeader( FILE* pFile, size_t nRecordCount, long* piRecordOffset, long* piContentOffset )
{
	int				bResult = 0;
	PAK_PKG_HEAD	pkgHeader = { 0 };
	long			nNewRecordOffset = 0, nNewContentOffset = 0;
	size_t			nWrite = 0, nRealWrite = 0;

	PROCESS_ERROR( pFile && piRecordOffset && piContentOffset );
	nNewRecordOffset = *piRecordOffset;
	nNewContentOffset = *piContentOffset;

	pkgHeader.szMagic[0] = 'L';
	pkgHeader.szMagic[1] = 'S';
	pkgHeader.nRecordCount = nRecordCount;

	nWrite = sizeof(pkgHeader);
	PROCESS_ERROR( _WriteFileAt( pFile, (char*)&pkgHeader, nWrite, &nRealWrite, nNewRecordOffset ) );
	PROCESS_ERROR( nWrite == nRealWrite );
	nNewRecordOffset += (long)nWrite;

	*piRecordOffset = nNewRecordOffset;
	*piContentOffset = nNewContentOffset;
	bResult = 1;
Exit0:
	return bResult;
}
int _LoadHeader( FILE* pFile, PPAK_PKG_HEAD pPkgHeader )
{
	int		bResult = 0;
	size_t	nRead = 0, nRealRead = 0;

	PROCESS_ERROR( pFile && pPkgHeader );

	nRead = sizeof(PAK_PKG_HEAD);
	PROCESS_ERROR( _ReadFile( pFile, (char*)pPkgHeader, nRead, &nRealRead ) );
	PROCESS_ERROR( nRealRead == nRead );

	bResult = 1;
Exit0:
	return bResult;
}

int _LoadRecords( FILE* pFile, PPAK_DIR_NODE_RECORD pPkgRecords, size_t nRecordCount )
{
	int		bResult = 0;
	size_t	nRead = 0, nRealRead = 0;

	PROCESS_ERROR( pFile && pPkgRecords );

	nRead = sizeof( PAK_DIR_NODE_RECORD ) * nRecordCount;
	PROCESS_ERROR( _ReadFile( pFile, (char*)pPkgRecords, nRead, &nRealRead ) );
	PROCESS_ERROR( nRead == nRealRead );

	bResult = 1;
Exit0:
	return bResult;
}

int _ExtractOneFile( FILE* pPkgFile, FILE* pExtractFile, PPAK_DIR_NODE_RECORD pRecord, PPAK_PKG pPkg, PPAK_DIR_NODE pCurDir, const char* pszFullName )
{
	int			bResult = 0;
	size_t		nWrite = 0, nRealWrite = 0;
	size_t		nRead = 0, nRealRead = 0;
	size_t		nReadContentLen = 0, nContentLen = 0;
	char		szBuffer[PAK_READ_BUFFER] = { 0 };
	long		iNewOffset = 0, iNewWriteOffset = 0;
	PPAK_DIR	psValue = NULL;

	PROCESS_ERROR( pPkgFile && pExtractFile && pRecord );
	PROCESS_ERROR( psValue = _GetDirNodeValue( pCurDir ) );
	
	iNewOffset = psValue->nContent;
	nContentLen = psValue->nContentLen;
	while( nReadContentLen < nContentLen )
	{
		if( nContentLen - nReadContentLen > PAK_READ_BUFFER )
			nRead = PAK_READ_BUFFER;
		else
			nRead = nContentLen - nReadContentLen;
		PROCESS_ERROR( _ReadFileAt( pPkgFile, szBuffer, nRead, &nRealRead, iNewOffset ) );
		PROCESS_ERROR( nRead == nRealRead );
		nWrite = nRead;
		PROCESS_ERROR( _WriteFileAt( pExtractFile, szBuffer, nWrite, &nRealWrite, iNewWriteOffset ) );
		PROCESS_ERROR( nWrite == nRealWrite );

		iNewOffset += (long)nRealWrite;
		iNewWriteOffset += (long)nRealWrite;
		nReadContentLen += nRealWrite;

		//Callback
		if( pPkg->apfnCallbacks[ON_EXTRACTFILE] )
			pPkg->apfnCallbacks[ON_EXTRACTFILE]( pCurDir, nReadContentLen, nContentLen, NULL );
	}
	bResult = 1;
Exit0:
	return bResult;
}

PPAK_DIR_NODE_RECORD _FindRecord( PPAK_DIR_NODE_RECORD pPkgRecords, size_t nRecordCount, size_t nID )
{
	PPAK_DIR_NODE_RECORD		pFindRecord = NULL;
	size_t				i = 0;
	
	PROCESS_ERROR( pPkgRecords );
	for ( i = 0; i < nRecordCount; i++ )
	{
		if( pPkgRecords[i].nID == nID )
		{
			pFindRecord = &pPkgRecords[i];
			break;
		}
	}
	
Exit0:
	return pFindRecord;
}

int EnumDirTreePackage( PPAK_PKG pPkg, EnumPakNodeCallback pfnCallback, void* pCallbackParam )
{
	int				bResult = 0;
	PPAK_STACK		pStack = NULL;
	PPAK_STACK_ITEM	pNewStackItem = NULL, pCurStackItem = NULL;
	PPAK_DIR_NODE	pDirNodeRoot = NULL;
	PPAK_DIR_NODE	pCurNode = NULL, pChildNode = NULL;
	PPAK_DIR		pCurPakDir = NULL;
	char*			pszFullPath = NULL;
	size_t			nFullPath = 0, nFullPathMax = PAK_FULLPATH_MAXLEN;

	PROCESS_ERROR( pDirNodeRoot = pPkg->pDirTree );
	PROCESS_ERROR( pfnCallback );
	PROCESS_ERROR( pStack = _NewStack() );
	PROCESS_ERROR( pNewStackItem = _NewStackItem() );
	pNewStackItem->pValue = pDirNodeRoot;
	PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
	pNewStackItem = NULL;

	PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathMax ) );

	while( pCurStackItem = _PopStack( pStack ) )
	{
		pCurNode = (PPAK_DIR_NODE)pCurStackItem->pValue;
		PROCESS_ERROR( _DelStackItem( pCurStackItem ) );
		pCurStackItem = NULL;

		PROCESS_ERROR( pCurNode );
		PROCESS_ERROR( pCurPakDir = (PPAK_DIR)pCurNode->psValue );
		if( DIRTYPE_DIR == pCurPakDir->nType )
		{
			nFullPath = nFullPathMax;
			if( !_GetDirNodeFullPath( pCurNode, pszFullPath, &nFullPath ) )
			{
				if( pszFullPath )
					free( pszFullPath );
				nFullPathMax = nFullPath;
				PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathMax ) );
				PROCESS_ERROR( _GetDirNodeFullPath( pCurNode, pszFullPath, &nFullPath ) );
			}
		}
		else
		{
			nFullPath = nFullPathMax;
			if( !_GetDirNodeFullName( pCurNode, pszFullPath, &nFullPath ) )
			{
				if( pszFullPath )
					free( pszFullPath );
				nFullPathMax = nFullPath;
				PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathMax ) );
				PROCESS_ERROR( _GetDirNodeFullName( pCurNode, pszFullPath, &nFullPath ) );
			}
		}
		pfnCallback( pCurNode, pCallbackParam );

		pChildNode = pCurNode->pChildPakDir;
		while( pChildNode )
		{
			PROCESS_ERROR( pNewStackItem = _NewStackItem() );
			pNewStackItem->pValue = pChildNode;
			PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
			pNewStackItem = NULL;
			pChildNode = pChildNode->pBrotherPakDir;
		}
	}
	
	bResult = 1;
Exit0:

	if( pszFullPath )
		free( pszFullPath );
	if( pNewStackItem )
	{
		_RemoveStackItem( pStack, pNewStackItem );
		_DelStackItem( pNewStackItem );
	}
	if( pStack )
		_DelStack( pStack );
	return bResult;
}

PPAK_PKG CreatePackage()
{
	int			bResult = 0;
	PPAK_PKG	pNewPkg = NULL;
	
	PROCESS_ERROR( pNewPkg = (PPAK_PKG)calloc( 1, sizeof(PAK_PKG) ) );

	bResult = 1;
Exit0:
	if( 0==bResult )
	{
		DeletePackage( pNewPkg );
		pNewPkg = NULL;
	}

	return pNewPkg;
}

int SetPackageValue( PPAK_PKG psPkg, PPAK_DIR_NODE psPakNode )
{
	int	bResutl = 0;

	PROCESS_ERROR( psPkg && psPakNode );
	psPkg->pDirTree = psPakNode;

	bResutl = 1;

Exit0:
	return bResutl;
}

int SavePackage( PPAK_PKG pPkg, const char* pszSaveFileName, SAVE_NODE_VALUE pfnSaveValue )
{
	int		bResult = 0;
	
	PROCESS_ERROR( pPkg && pszSaveFileName );
	PROCESS_ERROR( _SavePakNode( pPkg, pPkg->pDirTree, pszSaveFileName, pfnSaveValue ) );

	bResult = 1;
Exit0:
	return bResult;
}
PPAK_PKG LoadPackage( const char* pszPkgFileName, LOAD_NODE_VALUE pfnLoadValue, PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnValueDestory)
{
	int					bResult = 0;
	PPAK_PKG			pPkg = NULL;
	PPAK_DIR_NODE_RECORD		pPkgRecords = NULL;
	PPAK_DIR_NODE		pDirRoot = NULL;
	size_t				nPkgRecordsCount = 0, nPkgRecordsBufferLen = 0;
	char*				pszPkgName = NULL;
	size_t				nPkgNameLen = 0;
	FILE*				pFile = NULL;

	PROCESS_ERROR( pszPkgFileName );
	PROCESS_ERROR( pFile = _OpenFile( pszPkgFileName, "rb" ) );
	PROCESS_ERROR( pPkg = (PPAK_PKG)calloc( 1, sizeof(PAK_PKG) ) );

	nPkgNameLen = strlen( pszPkgFileName );
	PROCESS_ERROR( pszPkgName = (char*)malloc( sizeof(char) * ( nPkgNameLen + 1 ) ) );
	strcpy( pszPkgName, pszPkgFileName );
	pPkg->pszPkgName = pszPkgName;
	pszPkgName = NULL;

	PROCESS_ERROR( _LoadHeader( pFile, &pPkg->PkgHeader ) );
	nPkgRecordsCount = pPkg->PkgHeader.nRecordCount;
	nPkgRecordsBufferLen = nPkgRecordsCount * sizeof( PAK_DIR_NODE_RECORD );
	PROCESS_ERROR( pPkgRecords = (PPAK_DIR_NODE_RECORD)malloc( nPkgRecordsBufferLen ) );
	PROCESS_ERROR( _LoadRecords( pFile, pPkgRecords, nPkgRecordsCount ) );
	pPkg->pPkgRecords = pPkgRecords;
	pPkg->nPkgRecordCount = nPkgRecordsCount;
	pPkgRecords = NULL;
	

	PROCESS_ERROR( pDirRoot = _GeneratePakNodeByRecords( pPkg->pPkgRecords, pPkg->nPkgRecordCount, pFile, pfnLoadValue, pfnValueCreator, pfnValueDestory ) );
	pPkg->pDirTree = pDirRoot;

	bResult = 1;
Exit0:
	if( 0==bResult )
	{
		if( pPkg )
			DeletePackage( pPkg );
		pPkg = NULL;

		if( pPkgRecords )
			free( pPkgRecords );
	}
	if( pszPkgName )
		free( pszPkgName );
	if( pFile )
		_CloseFile( pFile );
	return pPkg;
}

int ExtractDirTreePackage( PPAK_PKG pPkg, const char* pszU8RootPath )
{
	int					bResult = 0;
	char*				pszRootPath = NULL, *pszNodePath = NULL, *pszFullPath = NULL;
	size_t				nRootPathLen = 0, nNodePath = 0, nNodePathMax = PAK_FULLPATH_MAXLEN;
	size_t				nFullPathLen = 0;
	PPAK_DIR_NODE		pRootDir = NULL;
	PPAK_DIR_NODE		pCurDirNode = NULL;
	PPAK_STACK			pStack = NULL;
	PPAK_STACK_ITEM		pNewStackItem = NULL, pCurStackItem = NULL;
	FILE*				pPkgFile = NULL, *pUnpakFile = NULL;
	size_t				nTotalExtractCount = 0, nCurExtractCount = 0;

	PROCESS_ERROR( pPkg && pPkg->pDirTree && pPkg->pPkgRecords && pPkg->pszPkgName && pszU8RootPath );
	pRootDir = pPkg->pDirTree;
	
	//打开包文件
	PROCESS_ERROR( pPkgFile = _OpenFile( pPkg->pszPkgName, "rb" ) );

	//修正路径，且创建不存在的解包路径
	nRootPathLen = strlen( pszU8RootPath ) + 2;
	PROCESS_ERROR( nRootPathLen );
	PROCESS_ERROR( pszRootPath = (char*)malloc( sizeof(char) * nRootPathLen ) );
	strcpy( pszRootPath, pszU8RootPath );
	if( pszRootPath[nRootPathLen-1] != '\\' )
	{
		//pszRootPath[nRootPathLen] = '\\';
		strcat( pszRootPath, "\\" );
	}
	if( !_IsDirExist( pszRootPath ) )
	{
		PROCESS_ERROR( _CreateDir( pszRootPath ) );
	}
	//节点路径最大长度
	PROCESS_ERROR( pszNodePath = (char*)malloc( nNodePathMax ) );
	//全路径最大长度
	nFullPathLen = nNodePathMax + nRootPathLen;
	PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathLen ) );

	//创建栈用于遍历包文件中的节点
	PROCESS_ERROR( pStack = _NewStack() );
	PROCESS_ERROR( pNewStackItem = _NewStackItem() );
	pNewStackItem->pValue = pRootDir;
	PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
	pNewStackItem = NULL;

	nCurExtractCount = 0;
	nTotalExtractCount = pPkg->nPkgRecordCount;
	while( pCurStackItem = _PopStack( pStack ) )
	{
		PPAK_DIR_NODE_RECORD	pPkgRecord = NULL;
		PPAK_DIR_NODE	pChildDirNode = NULL;
		PPAK_DIR		pCurPakDir = NULL;

		pCurDirNode = (PPAK_DIR_NODE)pCurStackItem->pValue;
		PROCESS_ERROR( _DelStackItem( pCurStackItem ) );
		pCurStackItem = NULL;
		PROCESS_ERROR(pPkgRecord = _FindRecord( pPkg->pPkgRecords, pPkg->nPkgRecordCount, pCurDirNode->nNodeID ));
		PROCESS_ERROR( pCurDirNode );
		PROCESS_ERROR( pCurPakDir = (PPAK_DIR)pCurDirNode->psValue );
		
		if( DIRTYPE_DIR == pCurPakDir->nType )
		{
			nNodePath = nNodePathMax;
			if( !_GetDirNodeFullPath( pCurDirNode, pszNodePath, &nNodePath ) )
			{
				if( pszNodePath )
					free( pszNodePath );
				PROCESS_ERROR( pszNodePath = (char*)malloc( nNodePath ) );
				nNodePathMax = nNodePath;
				PROCESS_ERROR( _GetDirNodeFullPath( pCurDirNode, pszNodePath, &nNodePath ) );
			}
			
			if( nFullPathLen < nNodePathMax + nRootPathLen )
			{
				if( pszFullPath )
					free( pszFullPath );
				nFullPathLen = nNodePathMax + nRootPathLen;
				PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathLen ) );
			}
			strcpy( pszFullPath, pszRootPath );
			strcat( pszFullPath, pszNodePath );

			//pre callback
			if( pPkg->apfnCallbacks[ON_PRE_EXTRACTFILE] )
			{
				pPkg->apfnCallbacks[ON_PRE_EXTRACTFILE]( pCurDirNode, nCurExtractCount, nTotalExtractCount, NULL );
			}

			PROCESS_ERROR( _CreateDir( pszFullPath ) );
		}
		else if( DIRTYPE_FILE == pCurPakDir->nType )
		{
			nNodePath = nNodePathMax;
			if( !_GetDirNodeFullName( pCurDirNode, pszNodePath, &nNodePath ) )
			{
				if( pszNodePath )
					free( pszNodePath );
				PROCESS_ERROR( pszNodePath = (char*)malloc( sizeof(char) * nNodePath ) );
				nNodePathMax = nNodePath;
				PROCESS_ERROR( _GetDirNodeFullName( pCurDirNode, pszNodePath, &nNodePath ) );
			}
			if( nFullPathLen < nNodePathMax + nRootPathLen )
			{
				if( pszFullPath )
					free( pszFullPath );
				nFullPathLen = nNodePathMax + nRootPathLen;
				PROCESS_ERROR( pszFullPath = (char*)malloc( sizeof(char) * nFullPathLen ) );
			}
			strcpy( pszFullPath, pszRootPath );
			strcat( pszFullPath, pszNodePath );

			PROCESS_ERROR( pUnpakFile = _OpenFile( pszFullPath, "wb" ) );

			//pre callback
			if( pPkg->apfnCallbacks[ON_PRE_EXTRACTFILE] )
			{
				pPkg->apfnCallbacks[ON_PRE_EXTRACTFILE]( pCurDirNode, nCurExtractCount, nTotalExtractCount, NULL );
			}
			PROCESS_ERROR( _ExtractOneFile( pPkgFile, pUnpakFile, pPkgRecord, pPkg, pCurDirNode, pszFullPath ) );
			PROCESS_ERROR( _CloseFile( pUnpakFile ) );
			pUnpakFile = NULL;
		}

		//调用回调函数，表示一个解包一个文件已经完成
		nCurExtractCount++;
		if( pPkg->apfnCallbacks[ON_POST_EXTRACTFILE] )
		{
			pPkg->apfnCallbacks[ON_POST_EXTRACTFILE]( pCurDirNode, nCurExtractCount, nTotalExtractCount, NULL );
		}

		pChildDirNode = pCurDirNode->pChildPakDir;
		while( pChildDirNode )
		{
			PROCESS_ERROR( pNewStackItem = _NewStackItem() );
			pNewStackItem->pValue = pChildDirNode;
			PROCESS_ERROR( _PushStack( pStack, pNewStackItem ) );
			pNewStackItem = NULL;
			pChildDirNode = pChildDirNode->pBrotherPakDir;
		}
	}

	bResult = 1;
Exit0:
	if( 0 == bResult )
	{
	
	}
	if( pPkgFile )
		_CloseFile( pPkgFile );
	if( pszRootPath )
		free( pszRootPath );
	if( pszNodePath )
		free( pszNodePath );
	if( pszFullPath )
		free( pszFullPath );
	if( pNewStackItem )
	{
		_RemoveStackItem( pStack, pNewStackItem );
		_DelStackItem( pNewStackItem );
	}
	if( pCurStackItem )
	{
		_RemoveStackItem( pStack, pCurStackItem );
		_DelStackItem( pCurStackItem );
	}
	if( pStack )
	{		
		_DelStack( pStack );
	}	
	return bResult;
}

int DeletePackage( PPAK_PKG pPkg )
{
	int bResult = 0;

	PROCESS_ERROR( pPkg );
	if( pPkg->pDirTree )
		DestroyPakNodeEx( pPkg->pDirTree );
	if( pPkg->pszPkgName )
		free( pPkg->pszPkgName );
	if( pPkg->pPkgRecords )
		free( pPkg->pPkgRecords );
	free( pPkg );

	bResult = 1;
Exit0:
	return bResult;
}

int SetPackageCallback( PPAK_PKG pPkg, int iType, PackageCallback pfnPkg )
{
	int	bResult = 0;
	
	PROCESS_ERROR( pPkg && pfnPkg && iType < MAX_PACKAGE_CALLBACK && iType >=0 );

	pPkg->apfnCallbacks[iType] = pfnPkg;
	bResult = 1;
Exit0:
	return bResult;
}

int _SaveValue( FILE* pFile, PPAK_DIR_NODE pDirNode, long iValueOffset, size_t* punValueLen, PPAK_PKG pPkg, void* psExtra )
{
	int					bResult = 0;
	PPAK_VALUE_RECORD	pValueRecord = NULL;
	size_t				unValueLen = 0;
	long				iValueRecordOffset = iValueOffset;
	long				iValueContentOffset = iValueOffset + sizeof( PAK_VALUE_RECORD );

	PPAK_DIR			pDir	=	NULL;
	size_t				nWrite	=	0,	nRealWrite	=	0;
	FILE*				pNodeFile = NULL;
	char*				pszFullName = NULL;
	size_t				nFullNameMax = PAK_FULLPATH_MAXLEN, nFullNameLen = 0;

	PROCESS_ERROR( pFile && pDirNode && punValueLen && pPkg );
	PROCESS_ERROR( pValueRecord = (PPAK_VALUE_RECORD)calloc( 1, sizeof( PAK_VALUE_RECORD ) ) );

	
	//记录该节点的名字信息并写入文件
	PROCESS_ERROR( pDir = (PPAK_DIR)pDirNode->psValue );

	nWrite = pDir->nNameLen;
	pValueRecord->nName = iValueContentOffset;
	pValueRecord->nNameLen = nWrite;
	PROCESS_ERROR( _WriteFileAt( pFile, (char*)pDir->pszName, nWrite, &nRealWrite, iValueContentOffset ) );
	PROCESS_ERROR( nRealWrite == nWrite );
	iValueContentOffset += (long)nWrite;
	unValueLen += nWrite;

	//记录该节点的内容信息并写入文件
	pValueRecord->iType = pDir->nType;
	if( DIRTYPE_FILE == pValueRecord->iType )
	{
		long	lNodeFileSize = 0;
		char	szReadBuffer[PAK_READ_BUFFER];
		size_t	nRealRead = 0;
		size_t	nReaded = 0, nTotalRead = 0;

		PROCESS_ERROR( pszFullName = (char*)malloc( sizeof(char) * nFullNameMax ) );
		nFullNameLen = nFullNameMax;
		if( !_GetDirNodeFullName( pDirNode, pszFullName, &nFullNameLen ) )
		{
			free( pszFullName );
			PROCESS_ERROR( pszFullName = (char*)malloc( sizeof(char) * nFullNameLen ) );
			nFullNameMax = nFullNameLen;
			PROCESS_ERROR( _GetDirNodeFullPath( pDirNode, pszFullName, &nFullNameLen ) );
		}

		PROCESS_ERROR( pNodeFile = _OpenFile( pszFullName, "rb" ) );
		PROCESS_ERROR( _GetFileSize( pNodeFile, &lNodeFileSize ) );

		pValueRecord->nConten = iValueContentOffset;
		pValueRecord->nContenLen = (size_t)lNodeFileSize;
		nTotalRead = lNodeFileSize > 0 ? (size_t)lNodeFileSize : 0;
		while( nReaded < nTotalRead )
		{
			PROCESS_ERROR( _ReadFile( pNodeFile, szReadBuffer, PAK_READ_BUFFER, &nRealRead ) );
			nReaded += (long)nRealRead;
			if( 0==nRealRead )
				break;

			PROCESS_ERROR( _WriteFileAt( pFile, szReadBuffer, nRealRead, &nRealWrite, iValueContentOffset ) );
			PROCESS_ERROR( nRealRead == nRealWrite );
			iValueContentOffset += (long)nRealWrite;

			if( pPkg->apfnCallbacks[ON_PACKFILE] )
				pPkg->apfnCallbacks[ON_PACKFILE]( pDirNode, nReaded, lNodeFileSize, NULL );
		}
		unValueLen += nReaded;

		_CloseFile( pNodeFile );
		pNodeFile = NULL;
	}
	else
	{
		pValueRecord->nConten = 0;
		pValueRecord->nContenLen = 0;
	}

	nWrite = sizeof( PAK_VALUE_RECORD );
	PROCESS_ERROR( _WriteFileAt( pFile, (char*)pValueRecord, nWrite, &nRealWrite, iValueRecordOffset ) );
	PROCESS_ERROR( nWrite == nRealWrite );
	unValueLen += sizeof( PAK_VALUE_RECORD );
	*punValueLen = unValueLen;
	
	bResult = 1;
	
Exit0:
	if ( pValueRecord )
	{
		free( pValueRecord );
	}
	if( pszFullName )
		free( pszFullName );
	return bResult;
}
void* _LoadValue( FILE* pFile, PPAK_DIR_NODE_RECORD pDirNodeRecord, void* psExtra )
{
	int bResult = 0;
	PAK_VALUE_RECORD sValueRecord = { 0 };
	PPAK_DIR psDir = NULL;
	char* pszDirName = NULL;
	size_t nRead, nRealRead;

	PROCESS_ERROR( pFile && pDirNodeRecord );
	nRead = sizeof( PAK_VALUE_RECORD );
	PROCESS_ERROR( _ReadFileAt( pFile, (char*)&sValueRecord, nRead, &nRealRead, pDirNodeRecord->nValueRecord ) );
	PROCESS_ERROR( nRead == nRealRead );

	nRead = sValueRecord.nNameLen;
	PROCESS_ERROR( pszDirName = (char*)malloc( nRead ) );
	PROCESS_ERROR( _ReadFileAt( pFile, pszDirName, nRead, &nRealRead, sValueRecord.nName ) );
	PROCESS_ERROR( nRealRead==nRead );

	PROCESS_ERROR( psDir = _CreatePakDir() );

	PROCESS_ERROR( _SetDirName( psDir, pszDirName ) );
	PROCESS_ERROR( _SetDirType( psDir, sValueRecord.iType ) );
	psDir->nContent = sValueRecord.nConten;
	psDir->nContentLen = sValueRecord.nContenLen;
	
	bResult = 1;	
	
Exit0:
	if ( 0==bResult )
	{
		_DestroyPakDir( psDir );
		psDir = NULL;
	}
	if ( pszDirName )
	{
		free( pszDirName );
		pszDirName = NULL;
	}
	return (void*)psDir;	
}
PPAK_DIR_NODE CreatePakNode( PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnValueDestroy )
{
	return _GetDirNode( pfnValueCreator, pfnValueDestroy );
}

void* GetPakNodeValue( PPAK_DIR_NODE psPakNode )
{
	return _GetDirNodeValue( psPakNode );
}

PAK_FUNC_CONTROL int AddPakNode( PPAK_DIR_NODE psPakNodeParent, PPAK_DIR_NODE psPakNode )
{
	return _AddDirNode( psPakNodeParent, psPakNode );
}
int DelPakNode( PPAK_DIR_NODE psPakNode )
{
	return _DeleteDirNode( psPakNode );
}
int DestroyPakNode( PPAK_DIR_NODE psPakNode )
{
	return _DestroyDirNode( psPakNode );
}
int DestroyPakNodeEx( PPAK_DIR_NODE psPakNode )
{
	return _DestroyDirNodeEx( psPakNode );
}

FILE* Pak_OpenFile( const char* pszu8FileName, const char* pszu8Mode )
{
	return _OpenFile( pszu8FileName, pszu8Mode );
}
int Pak_ReadFile( FILE* hFile, char* pstrReadBuffer, size_t nReadLen, size_t* pnReadLen )
{
	return _ReadFile( hFile, pstrReadBuffer, nReadLen, pnReadLen );
}
int Pak_ReadFileAt( FILE* hFile, char* pstrReadBuffer, size_t nReadLen, size_t* pnReadLen, long lPos )
{
	return _ReadFileAt( hFile, pstrReadBuffer, nReadLen, pnReadLen, lPos );
}
int Pak_WriteFile( FILE* hFile, char* pstrWriteBuffer, size_t nWriteLen, size_t* pnWriteLen )
{
	return _WriteFile( hFile, pstrWriteBuffer, nWriteLen, pnWriteLen );
}
int Pak_WriteFileAt( FILE* hFile, char* pstrWriteBuffer, size_t nWriteLen, size_t* pnWriteLen, long lPos )
{
	return _WriteFileAt( hFile, pstrWriteBuffer, nWriteLen, pnWriteLen, lPos );
}
int Pak_SetFilePos( FILE* hFile, long lFilePos, int iBegin )
{
	return _SetFilePos( hFile, lFilePos, iBegin );
}
int Pak_GetFilePos( FILE* hFile, long* plFilePos )
{
	return _GetFilePos( hFile, plFilePos );
}
int Pak_GetFileSize( FILE* hFile, long* plSize )
{
	return _GetFileSize( hFile, plSize );
}
int Pak_CloseFile( FILE* hFile )
{
	return _CloseFile( hFile );
}

//Last line for linux

